package com.csthink.auditlog.repository;

import com.csthink.auditlog.domain.AuditLog;
import com.csthink.auditlog.dto.AuditLogQueryParamDTO;
import com.csthink.auditlog.dto.PageResultDTO;
import com.csthink.auditlog.enums.AuditLogBusinessEnum;
import com.csthink.common.infrastructure.util.IDGenerator;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @author <a href="mailto:security.2009@live.cn">Mars</a>
 * @since 2023-09-12
 */
@Slf4j
public class AbstractEsAuditLogRepository {

    private static final String[] FETCH_SOURCE_WEB = {"accountId", "logTime", "action", "category", "operatorId", "operatorInfo", "detail", "operatorType"};

//    protected RestHighLevelClient esClient;

//    protected AuditLogProducer auditLogProducer;

//    protected abstract String getReadIndexName();

//    protected abstract AuditLogBusinessEnum getBusiness();


    protected AuditLog save(AuditLog auditLog) throws IOException {
        if (StringUtils.isBlank(auditLog.getId())) {
            auditLog.setId(IDGenerator.getId());
        }
        // todo asyncmq
//        auditLogProducer.produce(Lists.newArrayList(auditLog), getBusiness());

        return auditLog;
    }

    protected List<String> batchSave(List<AuditLog> auditLogList) throws IOException {
        List<String> ids = Lists.newArrayList();
        if (CollectionUtils.isEmpty(auditLogList)) {
            return ids;
        }
        for (AuditLog auditLog: auditLogList) {
            if (StringUtils.isBlank(auditLog.getId())) {
                auditLog.setId(IDGenerator.getId());
            }
        }
        // todo asyncmq
//        auditLogProducer.produce(auditLogList, getBusiness());
        return ids;
    }

    protected PageResultDTO<AuditLog> query(AuditLogQueryParamDTO queryParam) throws IOException {
        // todo query from es
        List<AuditLog> auditLogs = List.of(new AuditLog());
        return new PageResultDTO<>(queryParam.getPageNumber(), queryParam.getPageSize(), 0, 0, auditLogs);

//        String indexName = getReadIndexName();
//        if (StringUtils.isBlank(indexName)) {
//            log.error("Not found audit log index name, please check your properties.");
//            return null;
//        }
//        SearchRequest request = new SearchRequest(getReadIndexName());
//        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//        int pageNo = queryParam.getPageNumber();
//        int pageSize = queryParam.getPageSize();
//        String sortFiled = StringUtils.isBlank(queryParam.getSortFiled()) ? "logTime" : queryParam.getSortFiled();
//        SortOrder sortOrder = StringUtils.isBlank(queryParam.getSortOrder()) ? SortOrder.DESC : SortOrder.fromString(queryParam.getSortOrder());
//        searchSourceBuilder.query(createQueryBuilder(queryParam))
//                .sort(new FieldSortBuilder(sortFiled).order(sortOrder))
//                .sort(new ScoreSortBuilder().order(sortOrder))
//                .from((pageNo - 1) * pageSize).trackTotalHits(true).size(pageSize);
//        request.source(searchSourceBuilder);
//        log.debug("audit log query: {E}", request.toString());
//        List<AuditLog> auditLogs = new ArrayList<>();
//        long total;
//        try {
//            SearchResponse response = esClient.search(request, getRequestOptions());
//            SearchHits hits = response.getHits();
//            total = hits.getTotalHits().value;
//            for (SearchHit h : hits) {
//                String json = Jackson2Util.tryToJson(h.getSourceAsMap());
//                AuditLog auditLog = Jackson2Util.toBean(json, AuditLog.class);
//                String detail = auditLog.getDetail();
//                String subAction = auditLog.getSubaction();
//                auditLog.setId(h.getId());
//                auditLog.setSubaction(I18nHelper.getLocaleContent(subAction));
//                auditLog.setDetail(I18nHelper.getLocaleContent(detail) + parseChanges(auditLog.getChanges()));
//                auditLogs.add(auditLog);
//            }
//        } catch (Exception e) {
//            log.error(String.format("fail to search: %s", queryParam), e);
//            throw e;
//        }
//        long pageCount = total/pageSize + (total%pageSize == 0 ? 0 : 1);
//        return new PageResultDTO<>(pageNo, pageSize, (int)pageCount, (int)total, auditLogs);
    }

//    private BoolQueryBuilder createQueryBuilder(AuditLogQueryParam queryParam) {
//        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
//        if (StringUtils.isNotEmpty(queryParam.getSource()))
//            queryBuilder.must(QueryBuilders.termQuery("source", queryParam.getSource()));
//        if (StringUtils.isNotEmpty(queryParam.getCategory()))
//            queryBuilder.must(QueryBuilders.termQuery("category", queryParam.getCategory()));
//        if (StringUtils.isNotEmpty(queryParam.getAction()))
//            queryBuilder.must(QueryBuilders.termQuery("action", queryParam.getAction()));
//        if (StringUtils.isNotEmpty(queryParam.getAccountId()))
//            queryBuilder.must(QueryBuilders.termQuery("accountId", queryParam.getAccountId()));
//        if(StringUtils.isNotEmpty(queryParam.getKeyword())) {
//            queryBuilder.must(QueryBuilders.matchQuery("changes.keyword", queryParam.getKeyword()));
//        }
//        if(StringUtils.isNotEmpty(queryParam.getOperatorInfo())) {
//            queryBuilder.must(QueryBuilders.wildcardQuery("operatorInfo", "*"+queryParam.getOperatorInfo()+"*"));
//        }
//        queryBuilder.must(QueryBuilders.rangeQuery("logTime").from(queryParam.getFrom()).to(queryParam.getTo()));
//        return queryBuilder;
//    }
//
//    private RequestOptions getRequestOptions() {
//        RequestOptions.Builder builder = RequestOptions.DEFAULT.toBuilder();
//        AuditLogBusiness auditLogBusiness = getBusiness();
//        builder.addHeader("x-zm-business-name", auditLogBusiness.getBusinessName());
//        builder.addHeader("x-zm-trackingid", TrackingUtil.getFromCurThread());
//        builder.addHeader("Authorization", generateJwtToken());
//        return builder.build();
//    }
//
//    private String generateJwtToken() {
//        Date now = new Date();
//        Date expire = new Date(now.getTime() + 60 * 60 * 1000L);
//        return ((AJWTSupport) SpringUtil.getBean("jwtExternalSupport")).builder(asyncBean.getIssuer(), JwtAudience.ASYNC).withIssuedAt(now).withExpiresAt(expire).buildWithPrefix();
//    }
//
//    private String parseChanges(List<Change> changes) {
//        if (CollectionUtils.isEmpty(changes)) {
//            return "";
//        }
//        String result = "";
//        for (Change change: changes) {
//            List<String> keys = Lists.newArrayList();
//            Map<String, Object> newValueMap = Maps.newHashMap();
//            Map<String, Object> oldValueMap = Maps.newHashMap();
//
//            try {
//                List<Change.KeyValue> oldValues = Jackson2Util.toList(change.getOldValueStr(), Change.KeyValue.class);
//                for (Change.KeyValue kv : oldValues) {
//                    // not show modify_time changes
//                    if (!"modifyTime".equals(kv.getKey())) {
//                        keys.add(kv.getKey());
//
//                        oldValueMap.put(kv.getKey(), kv.getValue());
//                    }
//                }
//
//                List<Change.KeyValue> newValues = Jackson2Util.toList(change.getNewValueStr(), Change.KeyValue.class);
//                for (Change.KeyValue kv : newValues) {
//                    if (!"modifyTime".equals(kv.getKey())) {
//                        newValueMap.put(kv.getKey(), kv.getValue());
//                    }
//                }
//            } catch (Exception e) {
//                log.warn("Failed to parse changes {} info as {}", changes, e);
//            }
//
//            if (CollectionUtils.isNotEmpty(keys)) {
//                for (String key: keys) {
//                    result += "\n" + I18nUtil.getMessage("alg.detail.common.change.desc", new Object[]{
//                            key,
//                            oldValueMap.get(key),
//                            newValueMap.containsKey(key)? newValueMap.get(key): ""
//                    });
//                }
//            }
//        }
//        return result;
//    }
}
